/*
 * Copyright Aduna (http://www.aduna-software.com/) (c) 1997-2007.
 *
 * Licensed under the Aduna BSD-style license.
 */

package edu.tju.commons.net;

import java.util.Collections;
import java.util.HashMap;
import java.util.Map;

/**
 * A ContentType consists of a mime-type, a character encoding and an optional
 * set of parameters.
 * 
 * @author Herko ter Horst
 */
public class ContentType {

	public static final String CHARSET_KEY = "charset";

	private String mimeType;

	private Map<String, String> parameterMap;

	/**
	 * Extracts the MIME type from a content type header.
	 */
	public static String getMimeType(String contentType) {
		ContentType ct = new ContentType(contentType);
		return ct.getMimeType();
	}

	/**
	 * Creates a new <tt>ContentType</tt> object for the header field value.
	 * 
	 * @param contentType
	 *            A Content-Type header field value.
	 */
	public ContentType(String contentType) {
		parameterMap = new HashMap<String, String>(4);
		processContentType(contentType);
	}

	/**
	 * Get the mime-type.
	 * 
	 * @return the mime-type
	 */
	public String getMimeType() {
		return mimeType;
	}

	/**
	 * Get the parameter value for the specified key
	 * 
	 * @param key
	 *            the key to look up
	 * @return the paramater value for the specified key, or null if there is no
	 *         value for the specified key
	 */
	public String getParameter(String key) {
		return parameterMap.get(key.toLowerCase());
	}

	/**
	 * Get the parameters
	 * 
	 * @return the parameters
	 */
	public Map<String, String> getParameters() {
		return Collections.unmodifiableMap(parameterMap);
	}

	/**
	 * Get the character encoding
	 * 
	 * @return the character encoding
	 */
	public String getCharset() {
		return getParameter(CHARSET_KEY);
	}

	private void processContentType(String contentType) {
		// Check if there are any parameters in the value
		int semiColonIdx = contentType.indexOf(';');

		if (semiColonIdx == -1) {
			// Content-Type field only specifies MIME type
			mimeType = contentType.trim();
		} else {
			// Content-Type field specifies extra parameters
			mimeType = contentType.substring(0, semiColonIdx).trim();

			int nextSemiColonIdx = contentType.indexOf(';', semiColonIdx + 1);
			while (nextSemiColonIdx != -1) {
				processParameter(contentType.substring(semiColonIdx + 1,
						nextSemiColonIdx));

				semiColonIdx = nextSemiColonIdx;
				nextSemiColonIdx = contentType.indexOf(';', semiColonIdx + 1);
			}

			processParameter(contentType.substring(semiColonIdx + 1));
		}
	}

	/**
	 * Parses a Content-Type parameter. If the parameter specifies a character
	 * set, then this character set is stored in the parameter map using the
	 * CHARSET_KEY.
	 */
	private void processParameter(String param) {
		// Equals sign split key and value:
		int equalsIdx = param.indexOf('=');

		if (equalsIdx >= 1) {
			String key = param.substring(0, equalsIdx).trim().toLowerCase();
			String value = param.substring(equalsIdx + 1).trim();

			parameterMap.put(key, value);
		} else {
			// Parameter is not a key-value pair, assume that it specifies the
			// character encoding, if none was set yet, as this is how some web
			// servers report it, e.g.: text/html;ISO-8859-1
			if (!parameterMap.containsKey(CHARSET_KEY)) {
				parameterMap.put(CHARSET_KEY, param.trim());
			}
		}
	}
}
